<!DOCTYPE html>
<html>
<head>
    <meta charset='utf-8'>
    <meta http-equiv='X-UA-Compatible' content='IE=edge'>
    <title>Page Title</title>
    <meta name='viewport' content='width=device-width, initial-scale=1'>
    <style type="text/css">
        canvas { border: 1px solid #cccccc; }
    </style>
    <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
</head>
<body>
    <canvas id="bubbleSort" width="1000" height="100"></canvas>
    <script>
        var arr = [3, 15, 5, 20, 4, 1, 7, 8]
        var canvas = document.getElementById('bubbleSort');
        var ctx = canvas.getContext('2d');

        function handleInitBubbleSort(arr) {
            for (var i=0; i<arr.length; i++) {
                ctx.fillStyle = "#add5e3";
                ctx.fillRect(i * 50, 100 - arr[i] * 3, 40, arr[i] * 3);
                ctx.font = "14px serif";
                ctx.fillStyle = "#000000";
                ctx.fillText(arr[i], i * 50 + 18, 100 - arr[i] * 3 - 5);
            }
        }

        function startHandleBubbleSort(arr, len, i) {
            console.log('第', i, '次循环');

            for (var j = 0; j < len - 1 - i; j++) {
                (function(a, b) {
                    setTimeout(function () {
                        if (b > 1) { // 恢复前一个
                            ctx.fillStyle = "#add5e3";
                            ctx.fillRect((a - 1) * 50, 100 - arr[a -1] * 3, 40, arr[a - 1] * 3);
                        }

                        ctx.fillStyle = '#24e278';
                        ctx.fillRect(a * 50, 100 - arr[a] * 3, 40, arr[a] * 3);
                        ctx.fillRect(b * 50, 100 - arr[b] * 3, 40, arr[b] * 3);

                        if (arr[a] > arr[b]) { // 两两交换
                            // 清空坐标数据
                            ctx.clearRect(a * 50, 0, 40, 100);
                            ctx.clearRect(b * 50, 0, 40, 100);

                            // 坐标交换
                            var temp = arr[b];
                            arr[b] = arr[a];
                            arr[a] = temp;

                            //console.log('a > b', arr[a], arr[b], ' | ', a, b)
                            //console.log('a: ', a * 50, 100 - arr[a] * 3, 40, arr[a] * 3)
                            //console.log('b: ', b * 50, 100 - arr[b] * 3, 40, arr[b] * 3)
                            ctx.fillStyle = '#24e278';
                            ctx.fillRect(a * 50, 100 - arr[a] * 3, 40, arr[a] * 3);
                            ctx.fillRect(b * 50, 100 - arr[b] * 3, 40, arr[b] * 3);

                            // 坐标上方字体交换
                            ctx.fillStyle = "#000000";
                            ctx.fillText(arr[a], a * 50 + 18, 100 - arr[a] * 3 - 5);
                            ctx.fillText(arr[b], b * 50 + 18, 100 - arr[b] * 3 - 5);
                            console.log('-----------');
                        }

                        if (b === len - 1 - i) {
                            console.log('渲染已完成', a, b);
                            if (a > 0) {
                                ctx.fillStyle = "#add5e3";
                                ctx.fillRect(a * 50, 100 - arr[a] * 3, 40, arr[a] * 3);
                            }

                            ctx.fillStyle = "#1b9ffc";
                            ctx.fillRect(b * 50, 100 - arr[b] * 3, 40, arr[b] * 3);

                            if (a === 0) {
                                ctx.fillRect(a * 50, 100 - arr[a] * 3, 40, arr[a] * 3);
                            }
                            
                            return startHandleBubbleSort(arr, arr.length, ++i);
                        }
                    }, 1000 * (a + 1));
                })(j, j+1)
            }
        }
        
        handleInitBubbleSort(arr)
        startHandleBubbleSort(arr, arr.length, 0);
    </script>
</body>
</html>